﻿using System;
using System.Collections.Generic;
using System.Text;
using Tauren.Business.DLL.Base;
using Tauren.Business.DLL.DictionaryDLL;
using Tauren.Business.DLL.Resouces;
using Tauren.Business.Entity.Config;
using Tauren.Business.Entity.Const;
using Tauren.Business.Entity.Enum;
using Tauren.Business.Entity.Global;
using Tauren.Business.Entity.Input;
using Tauren.Business.Entity.Model;
using Tauren.Business.Infrastructure.Globals;
using System.Linq;
using System.Transactions;
using Tauren.Business.Entity.Output;

namespace Tauren.Business.Service.DictionaryBLL
{
    /// <summary>
    /// 字典
    /// </summary>
    public class DictionaryService : Base.BaseService, IDictionaryService
    {
        private IDictionaryBusiness business;
        public DictionaryService(IDictionaryBusiness _business, IConnectionBLLBase connectionBLL, IMenuResourcesBusiness resourcesBusiness) : base(_business, connectionBLL, resourcesBusiness)
        {
            this.business = _business;
            this.ResourcesInfo = this.GetResources(GlobalConst.RESOURCES_FLAG_MODULE_DICTIONARY_KEY);
            this.JudePrmission(GlobalConst.RESOURCES_FLAG_MODULE_DICTIONARY_KEY.ToLower());
        }

        public IResponseMessage Add(Dictionary_Input data)
        {
            if (!HavePermission) return ErrorType.BUSINESS_WITHOUT_PERMISSION.Failure(this.CommonText(ErrorType.BUSINESS_WITHOUT_PERMISSION));
            if (data is null) return GlobalErrorType.GLOBAL_NOT_FOUND_INPUT_DATA.Failure(this.CommonText(GlobalErrorType.GLOBAL_NOT_FOUND_INPUT_DATA));
            var codes = business.IsPermissionCodeRepeat(0, data.Code);
            if (codes) return GlobalErrorType.GLOBAL_REPEAT_CODE.Failure(this.CommonText(GlobalErrorType.GLOBAL_REPEAT_CODE));
            int Msg = 0;
            string lan = "";
            bool repeat = ValueRepeat(data.Res, out Msg, out lan);
            if (!repeat) return Msg.Failure(string.Format(this.CommonText(Msg), lan));
            Dictionary dictionary;
            ToModel(data, out dictionary);
            dictionary.Enable = true;
            dictionary.Sequence = business.GetSeq();
            dictionary.Creator = this.Global.EmpId;
            dictionary.Modifier = this.Global.EmpId;
            dictionary.Creatdate = DateTime.Now;
            dictionary.Modifdate = DateTime.Now;
            using (TransactionScope ts = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions() { IsolationLevel = IsolationLevel.ReadUncommitted }))
            {
                bool b = true;
                long id = business.Add(dictionary);
                if (id > 0 && data.Res.Any())
                {
                    List<Entity.Model.DictionaryRes> dictionaryRes;
                    ToModel(data.Res, out dictionaryRes);
                    b = business.AddRes(dictionaryRes, id);
                    foreach (var item in dictionaryRes)
                    {
                        item.DicId = id;
                        AddEmpsRdis(item);
                    }
                }
                if (b)
                {
                    ts.Complete();
                    return "".OnSucceed(this.CommonText(GlobalErrorType.GLOBAL_SAVE_SUCCESSINFO.ToString()));
                }
                else return GlobalErrorType.GLOBAL_SAVE_FAILURE.OnSucceed(this.CommonText(GlobalErrorType.GLOBAL_SAVE_FAILURE));
            }
        }

        public IResponseMessage Config(string PageType)
        {
            if (!HavePermission) return ErrorType.BUSINESS_WITHOUT_PERMISSION.Failure(this.CommonText(ErrorType.BUSINESS_WITHOUT_PERMISSION));
            List<OutPutConfig> Fields = new List<OutPutConfig>();

            OutPutConfig config = new OutPutConfig();
            config.Label = this.Resources("thcode");
            config.FieldKey = "code";
            config.MenuCode = GlobalConst.RESOURCES_FLAG_MODULE_PERMISSION_KEY.ToLower();
            config.ControlType = ControlType.text;
            config.Show = true;
            config.Editor = PageType != "view" && PageType != "edit";
            config.Required = PageType != "view" && PageType != "edit";
            Dictionary<object, object> rule = new Dictionary<object, object>();
            if (PageType != "view")
            {
                #region 添加验证规则

                rule.Add("required", true);
                rule.Add("message", this.Resources("coderequired"));
                rule.Add("trigger", "blur");
                config.Rules.Add(rule);
                ///长度
                rule = new Dictionary<object, object>();
                rule.Add("min", 1);
                rule.Add("max", 30);
                rule.Add("message", this.Resources("codemax"));
                rule.Add("trigger", "blur");
                config.Rules.Add(rule);
                ///正则
                rule = new Dictionary<object, object>();
                rule.Add("pattern", "^([a-zA-Z0-9]){1,30}$");
                rule.Add("message", this.Resources("codedregx"));
                rule.Add("trigger", "blur");
                config.Rules.Add(rule);
            }
            Fields.Add(config);
            #endregion
            config = new OutPutConfig();
            config.FieldKey = "res";
            config.MenuCode = GlobalConst.RESOURCES_FLAG_MODULE_PERMISSION_KEY.ToLower();
            config.ControlType = ControlType.records;
            config.Show = true;
            config.Label = Resources("thname");
            config.Editor = PageType != "view";
            //BuliedChildConfig(config.ChildFields, PageType);
            BuliedTableResConfig(config.Tables, PageType);
            Fields.Add(config);
            config = new OutPutConfig();
            config.Label = this.Resources("thtype");
            config.FieldKey = "type";
            config.MenuCode = GlobalConst.RESOURCES_FLAG_MODULE_KEY.ToLower();
            config.ControlType = ControlType.parameter;
            config.Show = true;
            config.Editor = PageType != "view";
            config.Required = PageType != "view";
            config.Options = new List<Options>() {
                new Options { Label=this.CommonText($"dictionary{DictionaryType.flow}"),Value= DictionaryType.flow.ToString().ToLower() },
                new Options { Label=this.CommonText($"dictionary{DictionaryType.emp}"),Value= DictionaryType.emp.ToString().ToLower() },
                new Options { Label=this.CommonText($"dictionary{DictionaryType.org}"),Value= DictionaryType.org.ToString().ToLower() },
                new Options { Label=this.CommonText($"dictionary{DictionaryType.pos}"),Value=DictionaryType.pos.ToString().ToLower() }
            };
            if (PageType != "view")
            {
                rule = new Dictionary<object, object>();
                rule.Add("required", true);
                rule.Add("message", this.Resources("typerequired"));
                rule.Add("trigger", "change");
                config.Rules.Add(rule);
            }
            Fields.Add(config);
            config = new OutPutConfig();
            config.Label = this.CommonText("thnote");
            config.FieldKey = "note";
            config.MenuCode = GlobalConst.RESOURCES_FLAG_MODULE_PERMISSION_KEY.ToLower();
            config.ControlType = ControlType.textarea;
            config.Show = true;
            config.Editor = PageType != "view";
            config.Required = PageType != "view" && PageType != "edit";
            rule = new Dictionary<object, object>();
            if (PageType != "view")
            {
                ///长度
                rule = new Dictionary<object, object>();
                rule.Add("min", 1);
                rule.Add("max", 200);
                rule.Add("message", this.Resources("notemax"));
                rule.Add("trigger", "blur");
                config.Rules.Add(rule);
            }
            Fields.Add(config);
            return Fields.Succeed();
        }

        public IResponseMessage Delete(long AutoID)
        {
            if (!HavePermission) return ErrorType.BUSINESS_WITHOUT_PERMISSION.Failure(this.CommonText(ErrorType.BUSINESS_WITHOUT_PERMISSION));
            var data = business.Get<Dictionary>(AutoID);
            if (data is null) return GlobalErrorType.GLOBAL_NOT_FOUND_DB_DATA.Failure(this.CommonText(GlobalErrorType.GLOBAL_NOT_FOUND_DB_DATA));
            data.Enable = false;
            data.HaveDelete = true;
            data.Modifier = Global.EmpId;
            data.Modifdate = DateTime.Now;
            bool b = business.Update<Dictionary>(data);
            if (b)
            {
                RemoveRdis(AutoID);
                return "".OnSucceed(this.Resources(GlobalErrorType.GLOBAL_DELETE_SUCCESSINFO));
            }
            else return GlobalErrorType.GLOBAL_DELETE_FAILURE.OnSucceed(this.CommonText(GlobalErrorType.GLOBAL_DELETE_FAILURE));
        }

        public IResponseMessage Edit(Dictionary_Input data)
        {
            if (!HavePermission) return ErrorType.BUSINESS_WITHOUT_PERMISSION.Failure(this.CommonText(ErrorType.BUSINESS_WITHOUT_PERMISSION));
            if (data is null) return GlobalErrorType.GLOBAL_NOT_FOUND_INPUT_DATA.Failure(this.CommonText(GlobalErrorType.GLOBAL_NOT_FOUND_INPUT_DATA));
            var singe = business.Get<Dictionary>(data.AutoId);
            if (singe is null) return GlobalErrorType.GLOBAL_NOT_FOUND_DB_DATA.Failure(this.CommonText(GlobalErrorType.GLOBAL_NOT_FOUND_DB_DATA));
            var codes = business.IsPermissionCodeRepeat(0, data.Code);
            if (codes) return GlobalErrorType.GLOBAL_REPEAT_CODE.Failure(this.CommonText(GlobalErrorType.GLOBAL_REPEAT_CODE));
            int Msg;
            string lan;
            bool repeat = ValueRepeat(data.Res, out Msg, out lan);
            if (!repeat) return Msg.Failure(string.Format(this.CommonText(Msg), lan));
            singe.Modifier = this.Global.EmpId;
            singe.Modifdate = DateTime.Now;
            singe.Note = data.Note;
            using (TransactionScope ts = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions() { IsolationLevel = IsolationLevel.ReadUncommitted }))
            {
                bool b = business.Update(singe);
                List<Entity.Model.DictionaryRes> dictionaryRes = new List<DictionaryRes>();
                if (b && data.Res.Any())
                {
                    ToModel(data.Res, out dictionaryRes);
                }
                b = business.AddRes(dictionaryRes, data.AutoId);
                if (b)
                {
                    foreach (var item in dictionaryRes)
                    {
                        item.DicId = singe.AutoId;
                        AddEmpsRdis(item);
                    }
                    ts.Complete();
                    return "".OnSucceed(this.CommonText(GlobalErrorType.GLOBAL_SAVE_SUCCESSINFO.ToString()));
                }
                else return GlobalErrorType.GLOBAL_SAVE_FAILURE.OnSucceed(this.CommonText(GlobalErrorType.GLOBAL_SAVE_FAILURE));
            }
        }

        public IResponseMessage Enable(long AutoID)
        {
            if (!HavePermission) return ErrorType.BUSINESS_WITHOUT_PERMISSION.Failure(this.CommonText(ErrorType.BUSINESS_WITHOUT_PERMISSION));
            var data = business.Get<Dictionary>(AutoID);
            if (data is null) return GlobalErrorType.GLOBAL_NOT_FOUND_DB_DATA.Failure(this.CommonText(GlobalErrorType.GLOBAL_NOT_FOUND_DB_DATA));
            data.Enable = !data.Enable; 
            data.Modifier = Global.EmpId;
            data.Modifdate = DateTime.Now;
            bool b = business.Update<Dictionary>(data);
            if (b)
            {
                RemoveRdis(AutoID);
                return "".OnSucceed(this.CommonText(data.Enable ? GlobalErrorType.GLOBAL_ENABLE_SUCCESSINFO : GlobalErrorType.GLOBAL_DISABLE_SUCCESSINFO));
            }
            else return data.Enable ? GlobalErrorType.GLOBAL_ENABLE_FAILURE.OnSucceed(this.CommonText(GlobalErrorType.GLOBAL_ENABLE_FAILURE)) : GlobalErrorType.GLOBAL_DISABLE_FAILURE.OnSucceed(this.CommonText(GlobalErrorType.GLOBAL_DISABLE_FAILURE));
        }

        public IResponseMessage Get(long AutoID)
        {
            if (!HavePermission) return ErrorType.BUSINESS_WITHOUT_PERMISSION.Failure(this.CommonText(ErrorType.BUSINESS_WITHOUT_PERMISSION));
            Dictionary dictionary = business.Get<Dictionary>(AutoID);
            Dictionary_OutPut _OutPut = new Dictionary_OutPut();
            _OutPut.Res = new List<DictionaryRes_OutPut>() { new DictionaryRes_OutPut() { Language = "", Value = "" } };
            if (dictionary != null)
            {
                ToViewModel(dictionary, out _OutPut);
                if (!(_OutPut is null))
                {
                    var res = business.GetRes(dictionary.AutoId);
                    if (res.Any())
                    {
                        List<DictionaryRes_OutPut> _OutPuts;
                        ToViewModel(res, out _OutPuts);
                        _OutPut.Res = _OutPuts;
                    }
                }
            }
            return _OutPut.Succeed();
        }

        public IResponseMessage Pages(QueryModel queryModel)
        {
            if (!HavePermission) return ErrorType.BUSINESS_WITHOUT_PERMISSION.Failure(this.CommonText(ErrorType.BUSINESS_WITHOUT_PERMISSION));
            TableListModel<PageDictionaryTable> tableListModel = new TableListModel<PageDictionaryTable>();
            List<TableListHeaderModele> Headers = new List<TableListHeaderModele>();
            Headers.Add(new TableListHeaderModele() { Key = "rowNo", Name = CommonText("rowNo"), Width = 50, Align = "center" });
            Headers.Add(new TableListHeaderModele() { Key = "autoId", Name = CommonText("autoid"), Width = 70, Hide = true, Type = "primary_key", Align = "center", SorTable = SortType.custom.ToString() });
            Headers.Add(new TableListHeaderModele() { Key = "parentId", Name = CommonText("autoid"), Width = 70, Hide = true,  Align = "center", SorTable = SortType.custom.ToString() });
            Headers.Add(new TableListHeaderModele() { Key = "code", Name = Resources("thcode"), Width = 200, Align = "left", SorTable = SortType.custom.ToString() });
            Headers.Add(new TableListHeaderModele() { Key = "name", Name = Resources("thname"), Align = "left", IsOperation = true });
            Headers.Add(new TableListHeaderModele() { Key = "parentName", Name = Resources("thparentname"), Align = "left" });
            Headers.Add(new TableListHeaderModele() { Key = "type", Name = Resources("thtype"), Width = 120, Align = "center", IsTag = true, SorTable = SortType.custom.ToString() });
            Headers.Add(new TableListHeaderModele() { Key = "dic_Enable", Name = CommonText("thstate"), IsTag = true, Width = 100, Align = "center", SorTable = SortType.custom.ToString() });
            Headers.Add(new TableListHeaderModele() { Key = "dic_Creator", Name = CommonText("diccreator"), Width = 120, Align = "center" });
            Headers.Add(new TableListHeaderModele() { Key = "dic_Creatdate", Name = CommonText("diccreatdate"), Width = 160, Align = "center" });
            Headers.Add(new TableListHeaderModele() { Key = "action", Name = "操作", Width = 160, Align = "center" });
            long Total = 0;
            List<PageDictionaryTable> Data = business.Pages(queryModel, out Total);
            if (Data.Any())
            {
                Data.ForEach(o =>
                {
                    o.Dic_Enable = CommonText(o.Enable ? GlobalConst.RESOURCES_CONTENT_ENABLE_KEY : GlobalConst.RESOURCES_CONTENT_DISABLE_KEY);
                    o.Dic_Creator = EmpDictionary.ContainsKey(o.Creator) ? EmpDictionary[o.Creator] : "";
                    o.Dic_Creatdate = o.Creatdate.Value.ToString(GlobalConst.DATE_FORMAT_SECONDS);
                    o.Row_Style = o.Enable ? "" : "danger";
                    o.ParentName = this.Dictionarys.ContainsKey(o.ParentId) ? this.Dictionarys[o.ParentId] : "";
                    o.Name = this.Dictionarys.ContainsKey(o.AutoId) ? this.Dictionarys[o.AutoId] : "";
                    o.Type = this.CommonText($"dictionary{o.Type}");
                    o.Operations = new List<SystemButton>();
                    if (Global.IsAdmin && (Buttons is null || !Buttons.Any()))
                    {
                        BuliderButtons(o.Operations, o.Code, o.AutoId, ButtomType.edit);
                        BuliderButtons(o.Operations, o.Code, o.AutoId, ButtomType.detaile);
                        BuliderButtons(o.Operations, o.Code, o.AutoId, !o.Enable ? ButtomType.enable : ButtomType.disable);
                        BuliderButtons(o.Operations, o.Code, o.AutoId, ButtomType.delete);
                    }
                    else
                    {
                        if (Buttons.Any(o => o.Location == ButtomLocation.center.ToString() && o.Value == ButtomType.edit.ToString()))
                            BuliderButtons(o.Operations, o.Code, o.AutoId, ButtomType.edit);
                        if (Buttons.Any(o => o.Location == ButtomLocation.center.ToString() && o.Value == ButtomType.detaile.ToString()))
                            BuliderButtons(o.Operations, o.Code, o.AutoId, ButtomType.detaile);
                        if (Buttons.Any(o => o.Location == ButtomLocation.center.ToString() && (o.Value == ButtomType.enable.ToString() || o.Value == ButtomType.disable.ToString())))
                            BuliderButtons(o.Operations, o.Code, o.AutoId, !o.Enable ? ButtomType.enable : ButtomType.disable);
                        if (Buttons.Any(o => o.Location == ButtomLocation.center.ToString() && o.Value == ButtomType.delete.ToString()))
                            BuliderButtons(o.Operations, o.Code, o.AutoId, ButtomType.delete);
                    }
                });
            }
            tableListModel.Body = Data;
            tableListModel.Total = Total;
            tableListModel.Header = Headers;
            if (Global.IsAdmin && (Buttons is null || !Buttons.Any()))
            {
                BuliderButtons(tableListModel.Operations, "", 0, ButtomType.add);
            }
            else
            {
                if (Buttons.Any(o => o.Value == ButtomType.add.ToString()))
                    BuliderButtons(tableListModel.Operations, "", 0, ButtomType.add);
            }
            return tableListModel.Succeed();
        }

        public IResponseMessage Template(string key)
        {
            return new DictionaryRes_OutPut() { Language = "", Value = "" }.Succeed();
        }

        public IResponseMessage Tree()
        {

            List<Dictionary> dictionaries = baseDLL.All<Dictionary>();
            List<Entity.Output.Dictionary_OutPut> dics;
            ToViewModel(dictionaries, out dics);
            List<GlobalTree> globalTrees = new List<GlobalTree>();
            if (dics != null && dics.Any())
                dics.Where(o => o.ParentId == 0 && !o.HaveDelete).ToList().ForEach(o =>
                {
                    globalTrees.Add(new GlobalTree()
                    {
                        Icon = o.GetIcons(),
                        Id = o.AutoId,
                        Label = this.Dictionarys.ContainsKey(o.AutoId) ? this.Dictionarys[o.AutoId] : "",
                        Code = o.Code,
                        ParentId = o.ParentId,
                        Children = GenerateChildTreeInfo(o.AutoId, dics),
                        UseNodeCss = !o.Enable || o.HaveDelete,
                    });
                });
            return globalTrees.Succeed();
        }

        private List<GlobalTree> GenerateChildTreeInfo(long autoId, List<Dictionary_OutPut> dics)
        {
            List<GlobalTree> _OutPuts = new List<GlobalTree>();
            List<Dictionary_OutPut> childMenus = dics.Where(o => !o.HaveDelete && o.ParentId == autoId && !o.HaveDelete).ToList();
            if (childMenus.Any())
            {
                childMenus.ForEach(o =>
                {
                    _OutPuts.Add(new GlobalTree()
                    {
                        Icon = o.GetIcons(),
                        Id = o.AutoId,
                        Label = this.Dictionarys.ContainsKey(o.AutoId) ? this.Dictionarys[o.AutoId] : "",
                        Code = o.Code,
                        ParentId = o.ParentId,
                        Children = GenerateChildTreeInfo(o.AutoId, dics),
                        UseNodeCss = !o.Enable || o.HaveDelete,
                    });
                });
            }
            return _OutPuts;
        }

        #region private
        private bool ValueRepeat(List<Entity.Input.DictionaryRes_Input> ChildFieldValues, out int Msg, out string lan)
        {
            bool b = true;
            Msg = 0;
            lan = "";
            var groups = ChildFieldValues.GroupBy(o => o.Language).Select(n => new { Language = n.Key, cout = n.Count() });
            foreach (var item in groups)
            {
                if (item.cout > 1)
                {
                    b = false;
                    Msg = GlobalErrorType.GLOBAL_LANGUAGE_REPEAT_ERROR;
                    lan = item.Language;
                    break;
                }
            }
            return b;
        }

        /// <summary>
        /// 将员工添加到redis
        /// </summary>
        /// <param name="model"></param>
        private void AddEmpsRdis(Entity.Model.DictionaryRes model)
        {
            string redisKey = $"{Global.TenementCode.ToUpper()}_{GlobalConst.DICTIONARYRES_FLAG_REDIS_KEY}";
            string redisHashField = $"{redisKey}_{model.Language.Replace("-", "_")}_{model.DicId}";
            if (!RedisClient.HashKeys(redisKey).Any())
            {
                ToDictionarys();
            }
            else
            {
                RedisClient.HashDelete(redisKey, redisHashField);
                RedisClient.HashSet(redisKey, redisHashField, model);
            }
        }
        /// <summary>
        /// 将员工从redis中移除
        /// </summary>
        /// <param name="model"></param>
        private void RemoveRdis(long dicId)
        {
            string redisKey = $"{Global.TenementCode.ToUpper()}_{GlobalConst.DICTIONARYRES_FLAG_REDIS_KEY}";
            string redisHashField = $"{redisKey}_zh_cn_{dicId}";
            RedisClient.HashDelete(redisKey, redisHashField);
            redisHashField = $"{redisKey}_en_{dicId}";
            RedisClient.HashDelete(redisKey, redisHashField);
        }

        protected override void BuliedTableResConfig(List<TableListHeaderModele> Headers, string pageType)
        {
            Dictionary<object, object> rule = new Dictionary<object, object>();
            rule.Add("required", true);
            rule.Add("message", this.Resources("resnamerequired"));
            rule.Add("trigger", "change");
            Headers.Add(new TableListHeaderModele()
            {
                Key = "language",
                Name = CommonText("language"),
                Align = "left",
                Options = this.Options,
                Rules = pageType != "view" ? new List<Dictionary<object, object>>() { rule } : new List<Dictionary<object, object>>(),
                Show = true,
                Editor = pageType != "view",
                ControlType = ControlType.parameter,
            });
            ///长度
            rule = new Dictionary<object, object>();
            rule.Add("min", 0);
            rule.Add("max", 200);
            rule.Add("message", this.Resources("resvaluelength"));
            rule.Add("trigger", "blur");
            Headers.Add(new TableListHeaderModele()
            {
                Key = "value",
                Name = Resources("thname"),
                IsOperation = true,
                Align = "center",
                Rules = pageType != "view" ? new List<Dictionary<object, object>>() { rule } : new List<Dictionary<object, object>>(),
                Show = true,
                Editor = pageType != "view",
                ControlType = ControlType.textarea
            });
        }
        #endregion
    }
}
